package com.smartahc.android.camera

import android.content.Intent
import android.graphics.*
import android.graphics.Bitmap.CompressFormat
import android.net.Uri
import android.os.*
import android.provider.MediaStore
import android.support.v4.content.FileProvider
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.View
import android.widget.Toast
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.smartahc.android.camera.MTCNN.Box
import com.smartahc.android.camera.MTCNN.MTCNN
import com.smartahc.android.camera.ternsorflow.Classifier
import com.smartahc.android.camera.ternsorflow.TensorFlowImageClassifier
//import com.smartahc.android.camera.yolov5.Box
import kotlinx.android.synthetic.main.activity_image_analysis.*
import kotlinx.android.synthetic.main.activity_main.*
import org.opencv.core.*
import java.io.File
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.util.*
import java.util.concurrent.Executor
import java.util.concurrent.ScheduledThreadPoolExecutor
import java.util.concurrent.ThreadFactory


class ImageAnalysisActivity  : AppCompatActivity(), View.OnClickListener {

    private val TAKE_PHOTO_REQUEST_CODE = 120
    private val PICTURE_REQUEST_CODE = 911

    private val CURRENT_TAKE_PHOTO_URI = "currentTakePhotoUri"

    private val INPUT_SIZE = 64//图片输入尺寸
    //图片数据规范化
    private val IMAGE_MEAN = 127
    private val IMAGE_STD = 127f
    //模型参数
    private val INPUT_NAME = "模型输入节点名称"
    private val OUTPUT_NAME = "模型输出节点名称"
    private val MODEL_FILE = "file:///android_asset/model/tensorflow模型.pb"
    private val LABEL_FILE = "file:///android_asset/model/标签.txt"

    private var executor: Executor? = null //线程
    private var currentTakePhotoUri: Uri? = null
    private var classifier: Classifier? = null //分类模型对象

    private lateinit var facd:MTCNN //检测模型对象

    //检测框坐标
    private var left_point = 0
    private var top_point = 0
    private var right_point = 0
    private var bottom_point = 0



    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_image_analysis)

        ivChoose.setOnClickListener(this)
        ivTakePhoto.setOnClickListener(this)

        // 避免耗时任务占用 CPU 时间片造成UI绘制卡顿，提升启动页面加载速度
        Looper.myQueue().addIdleHandler(idleHandler)
    }

    override fun onSaveInstanceState(outState: Bundle?) {
        outState?.putParcelable(CURRENT_TAKE_PHOTO_URI, currentTakePhotoUri)
        super.onSaveInstanceState(outState)
    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
        super.onRestoreInstanceState(savedInstanceState)
        if (savedInstanceState != null) {
            currentTakePhotoUri = savedInstanceState.getParcelable(CURRENT_TAKE_PHOTO_URI)
        }
    }

    /*
    * ##################################################################################################################################################################################
    * */
    /**
     * 主线程消息队列空闲时（视图第一帧绘制完成时）处理耗时事件
     */
    private var idleHandler: MessageQueue.IdleHandler = MessageQueue.IdleHandler {
        if (classifier == null) {
            // 创建 Classifier
            classifier = TensorFlowImageClassifier.create(this@ImageAnalysisActivity.assets,
                    MODEL_FILE, LABEL_FILE, INPUT_SIZE, IMAGE_MEAN, IMAGE_STD, INPUT_NAME, OUTPUT_NAME)
        }

//        加载检测权重
        facd = MTCNN(this@ImageAnalysisActivity.assets)

    // 初始化线程池
        executor = ScheduledThreadPoolExecutor(1, ThreadFactory { r ->
            val thread = Thread(r)
            thread.isDaemon = true
            thread.name = "ThreadPool-ImageClassifier"
            thread
        })

        false
    }

    /*
    * ##################################################################################################################################################################################
    * */

    override fun onClick(view: View) {
        when (view.id) {
            R.id.ivChoose -> choosePicture()
            R.id.ivTakePhoto -> takePhoto()
            else -> {
            }
        }
    }

    /**
     * 选择一张图片并裁剪获得一个小图
     */
    private fun choosePicture() {
        val intent = Intent(Intent.ACTION_GET_CONTENT)
        intent.type = "image/*"
        startActivityForResult(intent, PICTURE_REQUEST_CODE)
    }

    /**
     * 使用系统相机拍照
     */
    private fun takePhoto() {
        openSystemCamera()
    }

    /**
     * 打开系统相机
     */
    private fun openSystemCamera() {
        //调用系统相机
        val takePhotoIntent = Intent()
        takePhotoIntent.action = MediaStore.ACTION_IMAGE_CAPTURE

        //这句作用是如果没有相机则该应用不会闪退，要是不加这句则当系统没有相机应用的时候该应用会闪退
        if (takePhotoIntent.resolveActivity(packageManager) == null) {
            Toast.makeText(this, "当前系统没有可用的相机应用", Toast.LENGTH_SHORT).show()
            return
        }

        val fileName = "TF_" + System.currentTimeMillis() + ".jpg"
        val photoFile = File(FileUtil.getPhotoCacheFolder(), fileName)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //通过FileProvider创建一个content类型的Uri
            currentTakePhotoUri = FileProvider.getUriForFile(this, "com.smartahc.android.camera.file", photoFile)
            //对目标应用临时授权该 Uri 所代表的文件
            takePhotoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        } else {
            currentTakePhotoUri = Uri.fromFile(photoFile)
        }

        //将拍照结果保存至 outputFile 的Uri中，不保留在相册中
        takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, currentTakePhotoUri)
        startActivityForResult(takePhotoIntent, TAKE_PHOTO_REQUEST_CODE)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (resultCode == RESULT_OK) {
            when (requestCode) {
                PICTURE_REQUEST_CODE -> // 处理选择的图片
                    handleInputPhoto(data!!.data)
                TAKE_PHOTO_REQUEST_CODE -> // 如果拍照成功，加载图片并识别
                    handleInputPhoto(currentTakePhotoUri)
            }
        }
    }
    /*
    *##################################################################################################################################################################################
    * */
    //裁切图片:依据矩形框裁切图片
    fun clipBitmap(bitmap: Bitmap, left: Int, top: Int, right: Int, bottom: Int): Bitmap{
        var left = left
        var top = top
        var right = right
        var bottom = bottom
//        saveImage(Bitmap.createBitmap(bitmap, left, top, right-left, bottom-top)) //保存图片
        return Bitmap.createBitmap(bitmap, left, top, right - left, bottom - top)
    }

    //保存图片到手机目录  /storage/emulated/0/Boohee/*.jpg
    fun saveImage(bmp: Bitmap) {
        val appDir: File = File(Environment.getExternalStorageDirectory(), "Boohee")
        if (!appDir.exists()) {
            appDir.mkdir()
        }
        val fileName = System.currentTimeMillis().toString() + ".jpg"
        val file = File(appDir, fileName)
        System.out.println("输出路径： " + file)
        try {
            val fos = FileOutputStream(file)
            bmp.compress(CompressFormat.JPEG, 100, fos)
            fos.flush()
            fos.close()
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }


    // 画矩形框
    private fun drawRectangles(imageBitmap: Bitmap, x1: Int, y1: Int, x2: Int, y2: Int) {
        var left: Int
        var top: Int
        var right: Int
        var bottom: Int
//        val mutableBitmap = imageBitmap.copy(Bitmap.Config.ARGB_8888, true)
        val canvas = Canvas(imageBitmap)
        //Canvas canvas = new Canvas(imageBitmap);
        val paint = Paint()
        left =x1
        top = y1
        right = x2
        bottom = y2
        paint.setColor(Color.RED)
        paint.setStyle(Paint.Style.STROKE) //不填充
        paint.setStrokeWidth(2F) //线的宽度
        canvas.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), paint)
        ivPicture.setImageBitmap(imageBitmap) //img: 定义在xml布局中的ImagView控件
        //img.setImageBitmap(imageBitmap);
    }

    /**
     * 处理图片
     * @param imageUri
     */
    private fun handleInputPhoto(imageUri: Uri?) {
        // 加载图片
        Glide.with(this@ImageAnalysisActivity).asBitmap().listener(object : RequestListener<Bitmap> {

            override fun onLoadFailed(e: GlideException?, model: Any, target: Target<Bitmap>, isFirstResource: Boolean): Boolean {
                Toast.makeText(this@ImageAnalysisActivity, "图片加载失败", Toast.LENGTH_SHORT).show()
                return false
            }

            override fun onResourceReady(resource: Bitmap, model: Any, target: Target<Bitmap>, dataSource: DataSource, isFirstResource: Boolean): Boolean {

                //检测人脸
                var box: Vector<Box> = facd.detectFaces(resource, 32)

                var a: Int
                var b: Int
                if (box.get(0).left() < 0) {
                    a = 0
                } else {
                    a = box.get(0).left()
                }
                if (box.get(0).top() < 0) {
                    b = 0
                } else {
                    b = box.get(0).top()
                }

                if( box.get(0).right() > a && box.get(0).bottom() > b){
                    drawRectangles(resource, a, b, box.get(0).right(), box.get(0).bottom())
//
//
//                //表情识别
                    startImageClassifier(clipBitmap(resource, a, b, box.get(0).right(), box.get(0).bottom()))
                }

                return false
            }
        }).load(imageUri).into(ivPicture)
        tvInfo.text = "Processing..."
    }

    /**
     * 开始图片识别匹配###########################################################################################################################################
     * @param bitmap
     */
    private fun startImageClassifier(bitmap: Bitmap) {
        var start_time:Long;
        executor?.execute{
            try {
                Log.i("111", Thread.currentThread().name + " startImageClassifier")
                val croppedBitmap = getScaleBitmap(bitmap, INPUT_SIZE)

                start_time = System.currentTimeMillis()

                val results = classifier?.recognizeImage(croppedBitmap)

                Log.i("111", "startImageClassifier results: $results")
                runOnUiThread { tvInfo.text = String.format("results: %s    run time:%d毫秒", results, System.currentTimeMillis() - start_time) }
            } catch (e: IOException) {
                Log.e("111", "startImageClassifier getScaleBitmap " + e.message)
                e.printStackTrace()
            }
        }
    }

    /*
    * ##################################################################################################################################################################################
    * */

    /**
     * 对图片进行缩放
     * @param bitmap
     * @param size
     * @return
     * @throws IOException
     */
    @Throws(IOException::class)
    private fun getScaleBitmap(bitmap: Bitmap, size: Int): Bitmap {
        val width = bitmap.width
        val height = bitmap.height
        val scaleWidth = size.toFloat() / width
        val scaleHeight = size.toFloat() / height
        val matrix = Matrix()
        matrix.postScale(scaleWidth, scaleHeight)

        return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true)
    }

}
